#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium.common.exceptions import TimeoutException
from selenium.common.exceptions import WebDriverException
from Utils.Logger import Logger
from Config.GlobalVariables import WAIT_IMPLICITY_TIMEOUT, WAIT_UNTIL_TIMEOUT, WAIT_UNTIL_NOT_TIMEOUT, WAIT_FREQUENCY


class Wait(object):

    def __init__(self, _driver):
        self.driver = _driver
        self.logger = Logger().get_logger()

    def implicitly_wait(self, timeout=WAIT_IMPLICITY_TIMEOUT):
        try:
            self.logger.debug("Set implicity wait time to {0}".format(str(timeout)))
            self.driver.implicitly_wait(timeout)
        except WebDriverException as e:
            self.logger.error("WebDriverException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def title_is(self, title, timeout=WAIT_UNTIL_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait title is {0}".format(str(title)))
            result = WebDriverWait(self.driver, timeout, frequency).until(
                ec.title_is(title), 'Title is not {0}'.format(title))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def title_is_not(self, title, timeout=WAIT_UNTIL_NOT_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait title is not {0}".format(title))
            result = WebDriverWait(self.driver, timeout, frequency).until_not(
                ec.title_is(title), 'Title is still {0}'.format(title))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def title_contains(self, title, timeout=WAIT_UNTIL_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait title contains {0}".format(title))
            result = WebDriverWait(self.driver, timeout, frequency).until(
                ec.title_contains(title), 'Title not contains {0}'.format(title))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.error("Exception: ")
            raise

    def title_not_contains(self, title, timeout=WAIT_UNTIL_NOT_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait title not contains {0}".format(title))
            result = WebDriverWait(self.driver, timeout, frequency).until_not(
                ec.title_contains(title), 'Title still contains {0}'.format(title))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def element_present(self, locator, timeout=WAIT_UNTIL_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait element is present")
            result = WebDriverWait(self.driver, timeout, frequency).until(
                ec.presence_of_element_located(locator), 'Element {0} not presents'.format(locator))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def element_not_present(self, locator, timeout=WAIT_UNTIL_NOT_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait element is not present")
            result = WebDriverWait(self.driver, timeout, frequency).until_not(
                ec.presence_of_element_located(locator), 'Element {0} still presents'.format(locator))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def element_clickable(self, locator, timeout=WAIT_UNTIL_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait element is clickable")
            result = WebDriverWait(self.driver, timeout, frequency).until(
                ec.element_to_be_clickable(locator), 'Element {0} not clickable'.format(locator))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def element_not_clickable(self, locator, timeout=WAIT_UNTIL_NOT_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait element is not clickable")
            result = WebDriverWait(self.driver, timeout, frequency).until_not(
                ec.element_to_be_clickable(locator), 'Element {0} still clickable'.format(locator))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def element_visible(self, locator, timeout=WAIT_UNTIL_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait element is visisble")
            result = WebDriverWait(self.driver, timeout, frequency).until(
                ec.visibility_of_element_located(locator), 'Element {0} not visible'.format(locator))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def element_not_visible(self, locator, timeout=WAIT_UNTIL_NOT_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait element is not visisble")
            result = WebDriverWait(self.driver, timeout, frequency).until(
                ec.visibility_of_element_located(locator), 'Element {0} still visible'.format(locator))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def frame_switchable(self, locator, timeout=WAIT_UNTIL_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait frame is available and switchable")
            result = WebDriverWait(self.driver, timeout, frequency).until(
                ec.frame_to_be_available_and_switch_to_it(locator), 'Frame {0} not switchable'.format(locator))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def frame_not_switchable(self, locator, timeout=WAIT_UNTIL_NOT_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait frame is not available or switchable")
            result = WebDriverWait(self.driver, timeout, frequency).until_not(
                ec.frame_to_be_available_and_switch_to_it(locator), 'Frame {0} still switchable'.format(locator))
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def alert_present(self, timeout=WAIT_UNTIL_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait alert is visisble")
            result = WebDriverWait(self.driver, timeout, frequency).until(ec.alert_is_present(), 'Alert not visible')
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise

    def alert_not_present(self, timeout=WAIT_UNTIL_NOT_TIMEOUT, frequency=WAIT_FREQUENCY):
        try:
            self.logger.debug("Wait alert is not visisble")
            result = WebDriverWait(self.driver, timeout, frequency).until_not(
                ec.alert_is_present(), 'Alert not visible')
            return result
        except TimeoutException as e:
            self.logger.warning("TimeoutException: {0}".format(e)[:-1])
            raise e
        except Exception:
            self.logger.exception("Exception: ", exc_info=True)
            raise
